Version 3/170429 of Vorple (for Glulx only) by Juhana Leinonen begins here. "Core functionality of Vorple, including JavaScript evaluation and adding HTML elements." Use authorial modesty. Chapter 1 - Run-time errors To throw Vorple run-time error (desc – text): say " *** Vorple run-time error: [desc] *** ". Chapter 2 - Interpreter handshake The file of Vorple Handshake is called "VpHndshk". Vorple support is truth state that varies. Vorple support is false. This is the detect interpreter's Vorple support rule: if the file of Vorple Handshake exists: write "Callooh!" to the file of Vorple Handshake; mark the file of Vorple Handshake as ready to read; if "[text of the file of Vorple Handshake]" is "Callay!": now Vorple support is true. The detect interpreter's Vorple support rule is listed before the when play begins stage rule in the startup rulebook. To decide whether Vorple/JavaScript is supported/available: if Vorple support is true, decide yes; decide no. To decide whether Vorple/JavaScript is not supported/available: if Vorple support is true, decide no; decide yes. To decide whether Vorple/JavaScript is unsupported/unavailable: decide on whether or not Vorple is not supported. Chapter 3 – JavaScript code execution Section 1 – Executing code The file of JavaScript Evaluation Input is called "VpJSEval". To execute JavaScript code/command (JavaScript code - text): if Vorple is supported: write JavaScript code to the file of JavaScript Evaluation Input; mark the file of JavaScript Evaluation Input as ready to read. Section 2 – Return values The file of JavaScript Return Value is called "VpJSRtrn". To decide which text is the value returned by the JavaScript code/command: if Vorple is not supported: decide on ""; decide on substituted form of "[text of the file of JavaScript Return Value]". To decide which text is the type of (source - text): if Vorple is not supported: decide on "nothing"; let rval be source; if rval is: -- "": decide on "nothing"; -- "undefined": decide on "nothing"; -- "null": decide on "nothing"; -- "true": decide on "truth state"; -- "false": decide on "truth state"; -- "NaN": decide on "NaN"; -- "Infinity": decide on "infinity"; -- "-Infinity": decide on "infinity"; let initial character be character number 1 in rval; let last character be character number (number of characters in rval) in rval; if initial character is: -- "'": if the number of characters in rval is 1 or the last character is not "'": decide on "unknown"; decide on "text"; -- "[bracket]": decide on "list"; -- "{": decide on "object"; if word number 1 in rval is "function": decide on "function"; if rval matches the regular expression "^\-?\d+(\.\d+)?$": decide on "number"; decide on "unknown". To decide which text is the text returned by the JavaScript code/command: if Vorple is not supported: decide on ""; let rval be the value returned by the JavaScript command; if the type of the value returned by the JavaScript command is not "text": decide on rval; replace character number (number of characters in rval) in rval with ""; replace character number 1 in rval with ""; decide on rval. [The algorithm that converts text to numbers has been adapted from the extension Guncho Mockup by Guncho Cabal.] To decide which number is text (T - text) converted into a number: let S be 1; let L be the number of characters in T; if L is 0, decide on 0; let negated be false; let previous-result be 0; if character number 1 in T is "-": let negated be true; let S be 2; let result be 0; repeat with N running from S to L: let C be character number N in T; let D be 0; if C is: -- "0": let D be 0; -- "1": let D be 1; -- "2": let D be 2; -- "3": let D be 3; -- "4": let D be 4; -- "5": let D be 5; -- "6": let D be 6; -- "7": let D be 7; -- "8": let D be 8; -- "9": let D be 9; -- ".": let first decimal be text character number N + 1 in T converted into a number; if first decimal > 5: increment result; else if first decimal is 5: if negated is false: increment result; otherwise unless T exactly matches the regular expression "\-\d+\.50*": increment result; break; let result be (result * 10) + D; if previous-result > result: throw Vorple run-time error "Number [T] exceeds Glulx number range"; decide on 0; now previous-result is result; if negated is true: decide on 0 - result; decide on result. To decide which number is the number returned by the JavaScript code/command: if Vorple is not supported: decide on 0; let rval be the value returned by the JavaScript command; if the type of the value returned by the JavaScript command is "text": now rval is the text returned by the JavaScript command; otherwise if the type of the value returned by the JavaScript command is not "number": throw Vorple run-time error "Trying to convert return value of type [type of the value returned by the JavaScript command] into a number"; decide on 0; decide on text rval converted into a number. To decide if the JavaScript code/command returned (x - truth state): if Vorple is not supported: decide on false; if the type of the value returned by the JavaScript command is not "truth state": throw Vorple run-time error "Trying to convert return value of type [type of the value returned by the JavaScript command] into a number"; decide on false; if the value returned by the JavaScript command is "true" and x is true: decide on true; if the value returned by the JavaScript command is "false" and x is false: decide on true; decide on false. Section 3 - Escaping text for JavaScript To decide which text is escaped (string - text): decide on escaped string using "" as line breaks. To decide which text is escaped (string - text) using (lb - text) as line breaks: let safe-string be text; repeat with X running from 1 to number of characters in string: let char be character number X in string; if char is "'" or char is "[apostrophe]" or char is "\": now safe-string is "[safe-string]\"; if char is "[line break]": now safe-string is "[safe-string][lb]"; otherwise: now safe-string is "[safe-string][char]"; decide on safe-string. Chapter 4 – HTML tags Section 1 - Opening and closing To open a/-- HTML tag (name - text) called (classes - text): execute JavaScript command "vorple.layout.openTag('[name]','[classes]')". To open a/-- HTML tag (name - text): open HTML tag name called "". To close the/a/-- HTML tag: execute JavaScript command "vorple.layout.closeTag()". Section 2 - Placing elements To place a/an/-- (element - text) element called (classes - text) reading (content - text): open HTML tag element called classes; say content; close HTML tag. To place a/an/-- (tag - text) element called (classes - text): place tag element called classes reading "". To place a/an/-- (tag - text) element reading (content - text): place tag element called "" reading content. To place a/an/-- (tag - text) element: place tag element called "" reading "". To place an/-- inline/-- element called (classes - text) reading (content - text): place "span" element called classes reading content. To place an/-- inline/-- element called (classes - text): place inline element called classes reading "". To place an/-- inline/-- element reading (content - text): place inline element called "" reading content. To place a/-- block level/-- element called (classes - text) reading (content - text): place "div" element called classes reading content. To place a/-- block level/-- element called (classes - text): place block level element called classes reading "". To place a/-- block level/-- element reading (content - text): place block level element called "" reading content. To place an/-- element called (classes - text) at the top level: execute JavaScript command "vorple.layout.focus('main#haven')"; place block level element called classes. Section 3 - Displaying content To display text (content - text) in all the/-- elements called (classes - text): let print-safe content be escaped content using "\n" as line breaks; execute JavaScript command "$('.[classes]').text('[print-safe content]')". To display text (content - text) in the/-- element called (classes - text): display text content in all elements called "[classes]:last". Section 4 - Output focus To set output focus to the/an/-- element called (target - text): execute JavaScript command "vorple.layout.focus('.[target]')". To set output focus to the/-- main window: execute JavaScript command "vorple.layout.focus('#window0')". Section 5 - Counting and testing for existence To decide which number is the number of elements called (classes - text): execute JavaScript command "$('.'+'[classes]'.split(' ').join('.')).length"; decide on the number returned by the JavaScript command. To decide if an/the/-- element called (classes - text) exists: if the number of elements called classes is greater than 0: decide yes; decide no. To decide if an/the/-- element called (classes - text) doesn't exist: if the element called classes exists: decide no; decide yes. Section 6 - Scrolling To scroll to an/the/-- element called (classes - text): execute JavaScript command "vorple.layout.scrollTo('.[classes]:last')". To scroll to the/-- end/bottom of the/-- page: execute JavaScript command "vorple.layout.scrollToEnd()". Chapter 5 - User Interface Setup The Vorple interface setup rules is a rulebook. This is the Vorple interface setup stage rule: if Vorple is supported: execute JavaScript command "window._vorpleSetupRulebookHasRun||false"; if the JavaScript command returned false: follow the Vorple interface setup rules; execute JavaScript command "window._vorpleSetupRulebookHasRun=true". The Vorple interface setup stage rule is listed before the when play begins stage rule in the startup rulebook. Chapter 6 - Prompt [This is an internal helper variable that shouldn't be changed manually. To change the prompt, changing the usual "command prompt" variable should work fine.] The Vorple prompt is text that varies. The Vorple prompt is "". Last before reading a command (this is the convert default prompt to Vorple prompt rule): if Vorple is supported: let new prompt be the substituted form of the command prompt; [this prevents any say phrases with side effects inside the command prompt from triggering twice] if the Vorple prompt is not the new prompt: now the Vorple prompt is the new prompt; execute JavaScript command "vorple.prompt.setPrefix('[escaped Vorple prompt]')". Last rule for clarifying the parser's choice (this is the change Vorple prompt when clarifying choice rule): follow the convert default prompt to Vorple prompt rule; make no decision. Last after asking which do you mean (this is the change Vorple prompt when asking which do you mean rule): follow the convert default prompt to Vorple prompt rule; make no decision. First rule for printing a parser error when the latest parser error is the I beg your pardon error (this is the change Vorple prompt when input is empty rule): follow the convert default prompt to Vorple prompt rule; make no decision. Include (- Replace PrintPrompt; -) before "Printing.i6t". Include (- [ PrintPrompt i; RunTimeProblemShow(); ClearRTP(); style roman; EnsureBreakBeforePrompt(); if( ~~(+ Vorple support +) ) TEXT_TY_Say( (Global_Vars-->1) ); ClearBoxedText(); ClearParagraphing(14); ]; -) after "Printing.i6t". Chapter 7 - Unique identifiers To decide which text is unique identifier: let id be "id"; repeat with X running from 1 to 3: let rnd be a random number from 1000 to 9999; now id is "[id][rnd]"; decide on id. Chapter 8 - UI blocking To block the user interface: execute JavaScript command "vorple.layout.block()". To unblock the user interface: execute JavaScript command "vorple.layout.unblock()". Chapter 9 - Window title First when play begins (this is the set window title to story title rule): execute JavaScript command "document.title='[escaped story title]'". Chapter 10 - Credits [The Vorple version is shown in the banner by default, but there is no obligation to display it or otherwise credit Vorple (other than good manners.) The rule can be removed with "The display Vorple credits rule is not listed in any rulebook."] First after printing the banner text (this is the display Vorple credits rule): if Vorple is supported: execute JavaScript command "vorple.version"; let version number be the text returned by the JavaScript command; say "Vorple version [version number] preview[line break]" (A). Vorple ends here. ---- DOCUMENTATION ---- The Vorple core extension defines the basic structure that's needed for the story file to communicate with the web browser, as well as other low-level rules and phrases that other extensions use to add more features to Vorple. Authors who are not familiar with JavaScript or who wish to just use the basic Vorple features can read only the first three chapters (Vorple setup, compatibility with offline interpreters and the brief note about the command prompt). The rest of this documentation handles more advanced usage. For more practical usage of Vorple, see other Vorple extensions that implement specific features like multimedia support and hyperlinks. Chapter: Vorple setup Every Vorple story must include at least one Vorple extension and the custom web interpreter. *: Include Vorple by Juhana Leinonen. Release along with the "Vorple" interpreter. All standard Vorple extensions already have the "Include Vorple" line, so it's not necessary to add it to the story project if at least one of the other extensions are used. In contrast to previous versions that were only for Z-Machine, version 3 of Vorple is for Glulx only. The project's story file format must be set to Glulx in Inform's Settings pane. At the time of release of the current, third version of Vorple, the latest Inform release 6M62 includes the older version 2 of Vorple which is not compatible with the new extensions. The latest Vorple interpreter template is in the same package as these extensions. Also note that old Vorple extensions are not compatible with the current version of Vorple. If you get en error message about an extension being for Z-Machine only, the project is trying to include an old extension. For more detailed instructions on how to get started see the documentation at the vorple-if.com website. Chapter: Compatibility with offline interpreters Even though Vorple can accomplish many things that are plain impossible to do with traditional interpreters, it's always a good idea to make the story playable text-only as well if at all possible. There are many players to whom a web interpreter or Vorple's features aren't accessible, and it's the Right Thing To Do to not exclude people if it's possible to include them. A story file can detect if it's being run on an interpreter that supports Vorple. The same story file can therefore be run on both the Vorple web interpreter and other interpreters that have text-only features and display substitute content if necessary. We can test for Vorple's presence with "if Vorple is supported": Instead of going north: if Vorple is supported: play sound file "marching_band.mp3"; otherwise: say "A marching band crossing the street blocks your way." (The above example uses the Vorple Multimedia extension.) The say phrase in the above example is called a "fallback" and it's displayed only in normal non-Vorple interpreters. All Vorple features do nothing by default if they're not supported by the interpreter, unless otherwise stated in the extension's documentation. If substitute content is not necessary, we don't need to specifically check for Vorple compatibility: Instead of going north: play sound file "marching_band.mp3". Many Vorple features can be replicated at least to some extent on standard Glulx interpreters, but in general Vorple extensions don't try to use those Glulx features as a default fallback, but opt to printing plain text where applicable or doing nothing at all. Authors can use their choice of Glulx extensions and the above mentioned "if Vorple is supported" checks to make fallbacks that are most suitable for their story. Chapter: The command prompt To gain more control over the command prompt, Vorple replaces the built-in prompt with its own. The process should be completely automated: changing the "command prompt" variable should change the Vorple prompt as well, apart from some fringe cases where the source text or an extension does something exotic with the Glulx prompt. The prompt and the player's command are printed on the screen with custom techniques so they will not be included in the usual story output flow. It means that Glulx extensions that capture output text will not be able to read them. The extension Vorple Command Prompt Control offers features to manipulate the command prompt and the interpreter's line input in general. Chapter: Embedding HTML elements We can embed simple HTML elements into story text with some helper phrases. place an "article" element; place a "h1" element called "title"; place a block level element called "inventory"; place an inline element called "name"; The previous example generates elements equivalent to this HTML markup:
The element's name should be one word only and a valid CSS class name. It's safest to only use letters, numbers, underscores and dashes. Text content can be added on creation: place a "h1" element called "title" reading "An exciting story"; place a "h2" element reading "Story so far:"; ...or after the elements have been created: say "You shall be known as "; place an inline element called "name"; display text "Anonymous Adventurer" in the element called "name"; This technique can be used to modify the story output later (see example "Scrambled Eggs"). If the text is included at the same time when creating the element, the default behavior in non-Vorple interpreters is to print the text normally. Text added later will not do anything. In other words, 'place a "h1" element called "title" reading "An exciting story"' will print "An exciting story" in all interpreters, but 'display text "Anonymous Adventurer" in the element called "name"' will not print anything in anywhere other than the Vorple interpreter. In the above examples element contents should be plain text only. Trying to add nested tags or text styles will lead to erratic behavior. For longer and more complex contents the tags can be opened and closed manually: Report reading the letter: open HTML tag "div" called "letter"; place "h2" element reading "Dear Esther,"; say "I'm writing to tell you..."; close HTML tag. When there are multiple elements with the same name, only the last element will be updated. This is to accommodate repeat actions and specifically UNDO which can easily generate duplicate content. To modify all elements, use the following phrase: display "Hello World!" in all elements called "greeting"; We can also test whether an element exists or not, or count the number of elements: let n be the number of elements called "greeting"; if an element called "greeting" exists: ... if an element called "greeting" doesn't exist: ... The extension Vorple Element Manipulation contains more tools for working with the HTML document. Finally, the Vorple interpreter uses a concept called "output focus" to decide where it should print the story text. Any HTML element* can have the output focus, and any text coming from the story will be appended to the end of that element. For example we can have a separate element where the player's inventory is printed: (* The element that has output focus must be able contain child elements, so void elements, for example or